package com.ahpu.lyf.hashtab;

import java.util.Scanner;

public class HashTabDemo {
    public static void main(String[] args) {
        HashTab hashTab = new HashTab();

        while (true) {
            Scanner scanner = new Scanner(System.in);
            System.out.println("add:添加一个Exp");
            System.out.println("del:删除一个Exp");
            System.out.println("update:更新一个Exp");
            System.out.println("list:打印所有在HashTab的Exp");
            System.out.println("exit:退出！");
            String key = scanner.next();
            switch (key) {
                case "add":
                    System.out.println("输入Exp的id");
                    int id = scanner.nextInt();
                    System.out.println("输入Exp的name");
                    String name = scanner.next();
                    Exp exp = new Exp(id, name);
                    hashTab.add(exp);
                    break;
                case "list":
                    hashTab.list();
                    break;
                case "del":
                    System.out.println("输入要删除的id");
                    int delId = scanner.nextInt();
                    hashTab.del(delId);
                    break;
                case "update":
                    System.out.println("输入要更新的Exp的id");
                    int updateId = scanner.nextInt();
                    System.out.println("输入要变更的name");
                    String updateName = scanner.next();
                    hashTab.update(new Exp(updateId,updateName));
                    break;
                case "exit":
                    System.exit(0);
                default:
                    System.out.println("指令不正确!");
                    break;
            }
        }
    }
}

/**
 * 管理每个链表
 */
class HashTab {
    //一个存放链表的数组
    private ExpLinkedList[] expLinkedLists;
    private Integer num;

    /**
     * 无参构造，默认初始化8个链表
     */
    public HashTab(){
        this.num = 8;
        expLinkedLists = new ExpLinkedList[num];
        //初始化链表头到数组内
        for (int i = 0; i < num; i++) {
            expLinkedLists[i] = new ExpLinkedList();
        }
    }

    /**
     * 初始化num个链表
     * @param num 要初始化的连表数
     */
    public HashTab(Integer num) {
        this.num = num;
        expLinkedLists = new ExpLinkedList[num];
        //初始化链表头数组内
        for (int i = 0; i < num; i++) {
            expLinkedLists[i] = new ExpLinkedList();
        }
    }

    /**
     * 添加Exp的方法
     * @param exp 要添加的Exp
     */
    public void add(Exp exp) {
        //判断该Exp应该放到哪个链表
        Integer hashVal = getHashVal(exp.getId());
        //添加Exp
        expLinkedLists[hashVal].add(exp);
    }

    /**
     * 根据id删除Exp的方法
     * @param id 要删除的Exp的id
     */
    public void del(Integer id){
        //判断该Exp在哪个链表
        Integer hashVal = getHashVal(id);
        //删除Exp
        expLinkedLists[hashVal].del(id);
    }

    /**
     * 根据id更新Exp信息的方法
     * @param exp 要更新的exp信息
     */
    public void update(Exp exp){
        //判断该Exp在哪个链表
        Integer hashVal = getHashVal(exp.getId());
        //更新Exp
        expLinkedLists[hashVal].update(exp);
    }

    /**
     * 打印HashTab所有链表存储的信息
     */
    public void list() {
        for (int i = 0; i < num; i++) {
            //打印每条链表存储的信息
            expLinkedLists[i].list(i);
            //换行
            System.out.println();
        }
    }

    /**
     * 根据id判断应该操作那条链表
     * @param id 要判断的id
     * @return 要操作的链表在链表数组的下标
     */
    public Integer getHashVal(Integer id) {
        return id % num;
    }
}

/**
 * 链表类
 */
class ExpLinkedList {
    //头结点信息，无参构造时，head默认为null
    private Exp head;

    /**
     * 向链表添加Exp的方法
     * @param exp 要添加的Exp
     */
    public void add(Exp exp) {
        //如果头结点为null，直接让头结点指向要添加的节点
        if (head == null) {
            head = exp;
            System.out.println(exp.toString()+"添加成功！");
        } else {
            //辅助节点，用于遍历
            Exp tempExp = head;
            //找到最后一个节点
            while (tempExp.getNext() != null) {
                tempExp = tempExp.getNext();
            }
            //让最后一个节点指向要添加的节点
            tempExp.setNext(exp);
            System.out.println(exp.toString()+"添加成功!");
        }
    }

    /**
     * 根据id删除节点的方法
     * @param id 要删除的节点id即Exp的id
     */
    public void del(Integer id){
        //head为null说明无信息
        if (head==null){
            System.out.println("无此id的Exp信息!");
        }else {
            //head的id等于要删除的id，直接让head指向head后一个节点
            if (head.getId().equals(id)){
                System.out.println(head.toString()+"信息已删除!");
                head=head.getNext();
                return;
            }
            //辅助节点，用于遍历，head一定不为null
            Exp tempExp=head;
            //如果当前节点的下一节点id是不是要删除的id且当前节点的后一个节点不指向null（说明此时节点不指向倒数第二个节点），则后移
            while (!tempExp.getNext().getId().equals(id)&&tempExp.getNext().getNext()!=null){
                tempExp=tempExp.getNext();
            }
            //处理节点指向倒数第二个节点的情况，此时判断最后一个节点是否为要删除的节点
            if (!tempExp.getNext().getId().equals(id)){
                System.out.println("无编号为"+id+"的Exp信息!");
            }else {
                System.out.println(tempExp.getNext().toString()+"信息已删除!");
                //处理当前节点的下一节点就是要删除的节点，让当前节点指向下一节点的后一个节点
                tempExp.setNext(tempExp.getNext().getNext());
            }
        }
    }

    /**
     * 根据id跟新节点信息的方法
     * @param exp 要更新的节点id及要更新的name
     */
    public void update(Exp exp){
        //空链表
        if (head==null){
            System.out.println("无此id的Exp信息!");
        }else {
            //辅助节点，用于遍历，head一定不为null
            Exp tempExp=head;
            //当前节点不是要更新的节点且不是最后一个节点则后移
            while (!tempExp.getId().equals(exp.getId()) &&tempExp.getNext()!=null)
                tempExp=tempExp.getNext();
            //循环结束，若当前节点就是要更新节点则更新name，否则说明此时节点指向最后一个节点，说明没有查找到要更新的节点id
            if (tempExp.getId().equals(exp.getId())){
                tempExp.setName(exp.getName());
                System.out.println("编号为"+exp.getId()+"的信息更新成功！更新后的Exp信息为"+tempExp);
            }else {
                System.out.println("无编号为"+exp.getId()+"的Exp信息!");
            }
        }
    }

    /**
     * 打印链表节点信息
     * @param no 第no条链表的信息
     */
    public void list(Integer no) {
        //空链表
        if (head == null) {
            System.out.printf("第%d条链表为空!", (no + 1));
        } else {
            System.out.printf("第%d条链表的数据：", (no + 1));
            //辅助节点，用于遍历
            Exp tempExp = head;
            while (true) {
                //打印节点信息
                System.out.printf(" => id=%d, name=%s", tempExp.getId(), tempExp.getName());
                //如果到最后一个节点则终止循环，否则后移
                if (tempExp.getNext() == null)
                    break;
                tempExp = tempExp.getNext();
            }
        }
    }
}

/**
 * 员工类
 */
class Exp {
    private Integer id;
    private String name;
    private Exp next;

    public Exp() {
    }

    public Exp(Integer id, String name) {
        this.id = id;
        this.name = name;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Exp getNext() {
        return next;
    }

    public void setNext(Exp next) {
        this.next = next;
    }

    @Override
    public String toString() {
        return "Exp{" +
                "id=" + id +
                ", name='" + name + '\'' +
                '}';
    }
}
